package math;

import java.util.Random;

public class Vecmath
{
    
    private Vecmath()
    {
    }
    
    
    public static final double COMPARISON_ERROR = 1E-8;
    
    public static final double[] AXIS_X = new double[] { 1.0, 0.0, 0.0 };
    public static final double[] AXIS_Y = new double[] { 0.0, 1.0, 0.0 };
    public static final double[] AXIS_Z = new double[] { 0.0, 0.0, 1.0 };
    
    private static final Random gen = new Random();
    
    
    public static boolean equals(double[] a, double[] b)
    {
        boolean dx = Math.abs(a[0] - b[0]) <= Vecmath.COMPARISON_ERROR;
        boolean dy = Math.abs(a[1] - b[1]) <= Vecmath.COMPARISON_ERROR;
        boolean dz = Math.abs(a[2] - b[2]) <= Vecmath.COMPARISON_ERROR;
        return (dx && dy && dz);
    }
    
    public static double componentSum(double[] a)
    {
        double compSum = a[0] + a[1] + a[2];
        return compSum;
    }
    
    public static double getRandIn(double lower, double upper)
    {
        double rand01 = gen.nextDouble();
        rand01 *= (upper - lower);
        rand01 += lower;
        return rand01;
    }
    
    public static double getRandGaussIn(double lower, double upper)
    {
        double rand01 = gen.nextGaussian();
        rand01 *= (upper - lower);
        rand01 += lower;
        return rand01;
    }
    
    public static double dotProd(double[] a, double[] b)
    {
        return a[0]*b[0] + a[1]*b[1] + a[2]*b[2];
    }
    
    public static double length(double[] a)
    {
        return Math.sqrt(Vecmath.dotProd(a, a));
    }
    
    public static double[] add(double[] a, double[] b)
    {
        return new double[] { a[0]+b[0], a[1]+b[1], a[2]+b[2] };
    }
    
    public static double[] subtract(double[] a, double[] b)
    {
        return new double[] { a[0]-b[0], a[1]-b[1], a[2]-b[2] };
    }
    
    public static double[] multiply(double[] a, double[] b)
    {
        return new double[] { a[0]*b[0], a[1]*b[1], a[2]*b[2] };
    }
    
    public static double[] crossProd(double[] a, double[] b)
    {
        return new double[]
        {
            a[1]*b[2] - a[2]*b[1], 
            a[2]*b[0] - a[0]*b[2], 
            a[0]*b[1] - a[1]*b[0]
        };
    }
    
    public static double[] reflect(double[] incident, double[] normal)
    {
        double dotFactor = 2.0 * Vecmath.dotProd(incident, normal);
        return new double[]
        {
            dotFactor * normal[0] - incident[0], 
            dotFactor * normal[1] - incident[1], 
            dotFactor * normal[2] - incident[2]
        };
    }
    
    public static double[] getCopyOf(double[] a)
    {
        return new double[] { a[0], a[1], a[2] };
    }
    
    
    
    public static void scale(double[] a, double[] scale)
    {
        Vecmath.scale(a, scale[0], scale[1], scale[2]);
    }
    
    public static void scale(double[] a, double xScale, double yScale, double zScale)
    {
        a[0] *= xScale;
        a[1] *= yScale;
        a[2] *= zScale;
    }
    
    public static void scale(double[] a, double xyzScale)
    {
        Vecmath.scale(a, xyzScale, xyzScale, xyzScale);
    }

    public static void translate(double[] a, double[] translation)
    {
        a[0] += translation[0];
        a[1] += translation[1];
        a[2] += translation[2];
    }
    
    public static void normalize(double[] a)
    {
        double rec_length = 1.0 / Vecmath.length(a);
        Vecmath.scale(a, rec_length);
    }
    
    public static void limitComponents(double[] a, double limitLow, double limitHigh)
    {
        for (int i = 0; i < a.length; i++)
        {
            if (a[i] < limitLow)
            {
                a[i] = limitLow;
            }
            else if (a[i] > limitHigh)
            {
                a[i] = limitHigh;
            }
        }
    }
    
    public static void printVec(double[] a)
    {
        System.out.println(Vecmath.toString(a));
    }
    
    public static String toString(double[] a)
    {
        return "( " + a[0] + ", " + a[1] + ", " + a[2] + " )";
    }
    
}

